# 参数文件路径
filename.par <- "E:/CAT/Item parameter file.csv"    # 题目参数文件路径
filename.resp <- "E:/CAT/Item Response file.csv"    # 应答数据文件路径
filename.theta <- ""                               # 外部提供的能力值文件路径
filename.content <- "E:/CAT/content balance.csv"   # 内容平衡控制文件路径

# 测试控制参数
model <- 1              # 项目反应模型：1=Logistic模型，2=Linear模型
D <- 1.0                # 刻度参数 D
simulateTheta <- F      # 是否模拟生成能力值
nSimulee <- 0           # 模拟生成的能力值数量（当 simulateTheta=T 时生效）
popMean <- 0            # 人群能力值均值（用于模拟）
popSD <- 1              # 人群能力值标准差（用于模拟）

# 能力估计参数
eapFullLength <- T      # 是否使用全银行 EAP 估计
ni <- 9                 # 题目数量
maxCat <- 5             # 题目最大分类数
minTheta <- -4          # 能力值范围下限
maxTheta <- 4           # 能力值范围上限
inc <- 0.10             # 能力值增量

# 测试停止条件
maxNI <- 9              # 最大题目数量
minNI <- 0              # 最小题目数量
maxSE <- 0.316          # 最大标准误差（停止条件）
topN <- 1               # 每次选择题目时考虑的前 N 个题目
exposure.control <- F   # 是否启用题目曝光率控制
stopSE <- 0.01          # 停止条件：SEM 减少量
continueSE <- 0.03      # 停止条件：SEM 减少量

# 题目选择参数
selection.method <- 2   # 题目选择方法：1-9（不同方法）
interim.Theta <- 1      # 临时能力估计方法：1=EAP，2=MLE
se.method <- 1          # 标准误差计算方法：1=后验分布，2=Fisher 信息
first.item.selection <- 1  # 第一道题目选择方法：1=随机，2=初始能力值，3=指定题目，4=外部能力值
first.at.theta <- 0     # 初始能力估计值（当 first.item.selection=2 时生效）
first.item <- 1         # 指定第一道题目的索引（当 first.item.selection=3 时生效）
ncc <- 0                # 内容分类数量（用于内容平衡）

# 读取题目参数
item.par <- read.csv(filename.par, sep = ",", header = FALSE, col.names = c("a", paste("cb", 1:(maxCat - 1), sep = ""), "NCAT"))

# 初始化变量
theta <- seq(minTheta, maxTheta, inc)
nq <- length(theta)
prior <- dnorm(theta)  # 正态分布先验

# 动态答题和能力值计算
run_CAT <- function(user_responses) {
  ni.given <- 0
  items.used <- numeric(maxNI)
  theta.current <- 0  # 初始能力估计值
  theta.history <- numeric(maxNI)
  se.history <- numeric(maxNI)

  while (ni.given < maxNI) {
    # 计算信息值
    array.info <- calcInfo(theta.current)
    info.index <- order(array.info, decreasing = TRUE)
    item.selected <- info.index[1]

    # 更新已使用的题目
    items.used[ni.given + 1] <- item.selected
    ni.given <- ni.given + 1

    # 获取用户对当前题目的响应
    resp <- user_responses[[item.selected]]

    # 更新能力估计
    estimates <- calcEAP(resp, ni.given)
    theta.current <- estimates$THETA
    theta.history[ni.given] <- theta.current
    se.history[ni.given] <- estimates$SEM

    # 检查是否满足停止条件
    if (estimates$SEM <= maxSE) break
  }

  list(theta = theta.current, SEM = estimates$SEM, items_used = items.used[1:ni.given])
}

# 计算信息值
calcInfo <- function(theta) {
  info <- numeric(ni)
  for (i in 1:ni) {
    ps <- numeric(NCAT[i] + 1)
    ps[1] <- 1
    ps[NCAT[i] + 1] <- 0
    for (k in 1:(NCAT[i] - 1)) {
      ps[k + 1] <- 1 / (1 + exp(-D * item.par[i, "a"] * (theta - item.par[i, paste("cb", k, sep = "")])))
    }
    prob <- numeric(NCAT[i])
    for (k in 1:NCAT[i]) {
      prob[k] <- ps[k] - ps[k + 1]
      info[i] <- info[i] + (D * item.par[i, "a"] * (ps[k] * (1 - ps[k]) - ps[k + 1] * (1 - ps[k + 1])))^2 / prob[k]
    }
  }
  info
}

# 计算EAP能力估计
calcEAP <- function(resp, ngiven) {
  LH <- rep(1, nq)
  for (i in 1:ngiven) {
    item <- items.used[i]
    prob <- item.par[item, paste("cb", resp[item], sep = "")]
    LH <- LH * prob
  }
  posterior <- prior * LH
  EAP <- sum(posterior * theta) / sum(posterior)
  SEM <- sqrt(sum(posterior * (theta - EAP)^2) / sum(posterior))
  list(THETA = EAP, SEM = SEM)
}